import Vue from 'vue';

let vueInstance = new Vue();
let emptyVNode = vueInstance.$createElement();
let VNodeConstructor = emptyVNode.constructor;
/**
 * @description: 判断是否为虚拟dom
 * @param {object} data 目标数据
 * @return: Boolean
 */
export function isVNode (data) {
  return data && data.constructor && data.constructor === VNodeConstructor;
}

/**
 * @description: 获取满足条件的 vnode
 * @param {Object} vnode 目标虚拟 dom
 * @param {Function} matchFn 查询条件
 * @return: Array 满足条件的虚拟 dom 合集
 */
export function queryVNodes (vnode, matchFn) {
  let result = [];
  if (matchFn(vnode)) {
    result.push(vnode);
  }

  // 当node节点是组件的时候，children 在 componentOptions 上
  let node = vnode.componentOptions ? vnode.componentOptions : vnode;
  let children = (node.children && node.children.length) ? node.children : null;

  // 找子级
  if (children) {
    children.forEach(child => {
      let childResult = queryVNodes(child, matchFn);
      result = result.concat(childResult);
    });
  }

  return result;
}

/**
 * @description: 获取虚拟表格满足条件的 vnode
 * @param {Object} vnode 目标虚拟 dom
 * @param {Function} matchFn 查询条件
 * @return: 满足条件的vnode
 */
export function queryVirtualTableVNodes (vnodes, matchFn = (node) => (node._vnode.children || []).length === 5) {
  const field = '$children'
  if (!Array.isArray(vnodes)) {
    vnodes = [vnodes]
  }
  function fn (vnodes) {
    for (let i = 0; i < vnodes.length; i++) {
      const vnode = vnodes[i]
      const res = matchFn(vnode)
      if (res) {
        return vnode._vnode
      }
      if (vnode[field] && vnode[field].length > 0) {
        return fn(vnode[field])
      }
    }
  }
  return fn(vnodes)
}

/**
 * @description: 获取子级的满足条件的 vnode
 * @param {Object} vnode 目标虚拟 dom
 * @param {function} matchFn 匹配函数
 * @return: Array 满足条件的虚拟 dom 合集
 */
export function queryChildVNodes (vnode, matchFn) {
  let result = [];
  if (!vnode || !matchFn) {
    return result;
  }

  if (vnode.children && vnode.children.length) {
    vnode.children.forEach(child => {
      if (matchFn(child)) {
        result.push(child);
      }
    });
  } else if (vnode.componentOptions && vnode.componentOptions.children && vnode.componentOptions.children.length) {
    vnode.componentOptions.children.forEach(child => {
      if (matchFn(child)) {
        result.push(child);
      }
    });
  }

  return result;
}

/**
 * @description: 获取节点的 text
 * @param {Object} vnode 目标虚拟 dom
 * @return: String
 */
export function getVNodeText (vnode) {
  let nodes = queryVNodes(vnode, node => {
    return (node.tag === undefined && !node.isComment)
  });
  return nodes.reduce((text, node) => {
    if (node && node.text) {
      text += node.text.trim();
    }
    return text;
  }, '');
}

/**
 * excel的限制
 * sheet文字长度：31（不限制中文或数字）
 * table名字长度：207（包含.xlsx文件后缀，不限制中文或数字）
 */
/**
 * @description: 重写字符串
 * 功能：
 * 1、默认，限制长度
 * 2、修改字符串，防止再一连串字符串中重名
 * @param {Object.Number} options.len 数字长度
 * @param {Object.Boolean} options.isRepeat 是否开启防重名
 * @param {Object.Function} options.repeatTextFun 传入index，返回对应的添加后缀，可传入null
 * @param {Object.String} options.beyondDisplay 超出显示文字，可传入空字符串
 * @return {Class}
 */
export class NameRewriting {
  constructor(options = {}) {
    const defaultOptions = {
      len: 31,
      isRepeat: true, // 是否开启防重名
      // 重命名后缀添加
      repeatTextFun: (index) => {
        return `（重命名${index}）`
      },
      beyondDisplay: '...'
    }

    this.beyondDisplay =
      typeof options.beyondDisplay === 'string'
        ? options.beyondDisplay
        : defaultOptions.beyondDisplay
    // 长度必须长于超出显示文字
    this.len =
      options.len && options.len > this.beyondDisplay.length ? options.len : defaultOptions.len
    this.isRepeat =
      typeof options.isRepeat === 'boolean' ? options.isRepeat : defaultOptions.isRepeat
    // 如果传入空，则使用默认
    this.repeatTextFun =
      typeof options.repeatTextFun === 'function'
        ? options.repeatTextFun
        : defaultOptions.repeatTextFun

    // 初始化
    this.repeatName = {}
    this.originalName = '' // 记录原名字
  }

  /**
   * @description: 将传入的合格字符串，经配置处理后返回
   * @param {String} name 需处理的字符串
   * @return {String} 合格：返回经处理字符串；不合格：强制转换为string返回
   */
  get (name) {
    // 无数据；非字符串；立即返回
    if (!name || typeof name !== 'string') return String(name)
    this.originalName = name
    // 1、先切割长度
    let result = this.lengthLimit(name)
    // 2、再去判断是否重复
    const count = this.record(result)
    // 3、如果重复，长度+6超过len，则切去6格；如果长度+6未超过len，则增加重命名
    if (count && this.isRepeat) {
      result = this.repeatLimit(count)
    }
    return result
  }

  /**
   * @description: 长度限制，如果超出len，则截取添加...
   * @param {String} name 需处理的名字
   * @return {String}
   */
  lengthLimit (name) {
    // 小于长度，返回
    if (name.length <= this.len) return name
    return `${name.slice(0, this.len - this.beyondDisplay.length)}${this.beyondDisplay}`
  }

  /**
   * @description: 重名限制，table内sheet不能重名
   * @param {Number} count 重名次数
   * @return {String}
   */
  repeatLimit (count = 1) {
    // 判断长度是否需要切割
    const less = this.len - this.repeatTextFun(count).length
    let name = less > 0 ? this.originalName.slice(0, less) : this.originalName
    // 最终名字
    name = `${name}${this.repeatTextFun(count)}`
    // 再次判断是否重名
    const againCount = this.record(name)
    // 如果有重名，重新记录count数
    return againCount ? this.repeatLimit(againCount) : name
  }

  /**
   * @description: 记录重名次数
   * @param {String} name 需处理的名字
   * @return {Number} 记录次数 0：第一次，1+：一次以上
   */
  record (name) {
    if (this.repeatName[name] || this.repeatName[name] === 0) {
      this.repeatName[name] += 1
    } else {
      this.repeatName[name] = 0
    }
    return this.repeatName[name]
  }
}
